#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <UIKit/UIApplication.h>
#import <SpringBoard/SBApplicationController.h>
#import <SpringBoard/SBApplication.h>
#import <LockInfo/Plugin.h>

#import "framework/FWCommon.h"
#import "framework/FWPlugin.h"
#import "framework/FWApplication.h"

#import "PICommon.h"
#import "PIPlugin.h"
#import "PIIntegration.h"
#import "PITodoPreview.h"
#import "PIContextList.h"
#import "PIContextSelectList.h"
#import "PINewTodo.h"
#import "PIListAccess.h"
#import "PIStatus.h"


const NSString* PIiPhoneIdentifier = @"pocketinformant";
const NSString* PIiPadIdentifier = @"pocketinformantiPad";


@implementation PIPlugin

@synthesize contexts, contextsString;


// ******************************************************************************************
#pragma mark -
#pragma mark Initialisation and object management

- (id)initWithApplication:(FWApplication*)app
{
    if ((self = [super initWithApplication:app])) {
        self.datasource = [[[PIListAccess alloc] init] autorelease];
        app.applicationDelegate = self;
        
        NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
        
        [center addObserver:self selector:@selector(update:) name:UIPasteboardChangedNotification object:nil];
    }
    
    return self;
}

- (void)dealloc
{
    [super dealloc];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Application status management

- (void)application:(FWApplication*)application updateApplicationPrefs:(NSDictionary*)prefs pluginPrefs:(FWPreferences*)pluginPrefs
{
    PIStatus* status = (PIStatus*)application.info;
    
    [PIIntegration updateColorsFromPrefs:prefs application:application];
    status.badgeOn = [pluginPrefs boolValue:kPIOptionsShowBadge withDefault:kPIOptionsShowBadgeDefault];
    
    // Turn off auto contexts if PI has turned them off
    if (![PIIntegration locationMonitoringForPrefs:prefs]) {
        if (status.isAutoContextOn) {
            status.autoContextOn = NO;
            status.autoContextAvailable = NO;
            status.captionValue = nil;
            
            // Clear any contexts we're using
            [application clearAttribute:kPIApplicationContextCurrent];
        }
    }
    else {
        status.autoContextAvailable = YES;
    }
}

- (NSObject*)objectForSQLRecord:(sqlite3_stmt*)sqlStatement withId:(NSInteger)sqlid application:(FWApplication*)application
{
    int version = sqlite3_column_int(sqlStatement, 0);
    NSLog(@"LI:PITodo: Detected PI database version %i", version);
    return @"OK";
}

static NSString* const kPublicAppRoot = @"/var/mobile";
static NSString* const kPIDBPath = @"/Documents/pidata.sqlite";
static NSString* const kPIPrefsPattern = @"/Library/Preferences/%@.plist";

- (BOOL)testDB:(FWApplication*)application path:(NSString*)path
{
    // Check the database appears to work
    NSString* test = @"select schemaversion from version";
    NSArray* value = FWDBGetRecords(test, 1, path, application, self);
    return (value != nil);
}    

- (BOOL)updateApplication:(FWApplication*)application
{
    if (!application.info)
        application.info = [[[PIStatus alloc] init] autorelease];

    Class cls = objc_getClass("SBApplicationController");
    SBApplicationController* ctr = [cls sharedInstance];
    
    NSLog(@"LI:PITodo: Searching for application: %@", PIiPhoneIdentifier);
    SBApplication* app = [ctr applicationWithDisplayIdentifier:PIiPhoneIdentifier];
    if (app == nil) {
        NSLog(@"LI:PITodo: Searching for application: %@", PIiPadIdentifier);
        app = [ctr applicationWithDisplayIdentifier:PIiPadIdentifier];
    }
    
    if (!app) {
        NSLog(@"LI:PITodo: No application found");
        return NO;
    }
    
    NSLog(@"LI:PITodo: Discovered application: %@", app);

    // Get the badge number if there is one
    Class displayCls = objc_getClass("SBDisplay");
    NSNumber* badge = [displayCls defaultValueForKey:@"SBApplicationBadgeKey"
                                   displayIdentifier:app.displayIdentifier
                                           urlScheme:app.urlScheme];
    if (badge) {
        NSLog(@"LI:PITodo: Initial badge value = %@", badge);
        ((PIStatus*)application.info).badgeValue = [badge stringValue];
    }
    
    NSString* path = [app.path stringByDeletingLastPathComponent];
    application.applicationPath = app.path;
    application.preferencesPath = [path stringByAppendingFormat:kPIPrefsPattern, app.displayIdentifier];
    application.databasePath = [path stringByAppendingString:kPIDBPath];
    
    application.pluginPreferencesPath = [kPublicAppRoot stringByAppendingString:@"/Library/Preferences/com.rja.lockinfo.PIPlugin.plist"];
    application.pluginBundle = [NSBundle bundleWithPath:@"/Library/LockInfo/Plugins/com.rja.lockinfo.PIPlugin.bundle"];

    NSLog(@"LI:PITodo: Application path = %@", application.applicationPath);
    NSLog(@"LI:PITodo: Application preferences path = %@", application.preferencesPath);
    NSLog(@"LI:PITodo: Application database path = %@", application.databasePath);
    NSLog(@"LI:PITodo: Application plugin preferences path = %@", application.pluginPreferencesPath);
    
    // Check the database appears to work
    if (![self testDB:application path:application.databasePath]) {
        NSLog(@"LI:PITodo: Database not readable at %@", application.databasePath);
                
        NSString* dbPath = [kPublicAppRoot stringByAppendingString:kPIDBPath];
        NSString* prefsPath = [kPublicAppRoot stringByAppendingFormat:kPIPrefsPattern, app.displayIdentifier];

        if ([self testDB:application path:dbPath]) {
            NSLog(@"LI:PITodo: Database unexpectedly found at %@", dbPath);
            application.databasePath = dbPath;
            application.preferencesPath = prefsPath;
        }
    }
    
    // Get initial config
    NSDictionary* prefs = [NSDictionary dictionaryWithContentsOfFile:application.preferencesPath];
    DebugLog(@"LI:PITodo: PI Preferences on startup = %@", prefs);
    
    // If PI has location contexts on then so should we
    PIStatus* status = (PIStatus*)application.info;
    status.autoContextOn = status.autoContextAvailable = [PIIntegration locationMonitoringForPrefs:prefs];
    
    NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
    [center addObserver:self
               selector:@selector(badgeUpdate:)
                   name:[app.bundleIdentifier stringByAppendingString:LIBadgeChangedNotification]
                 object:nil];
    
    NSLog(@"LI:PITodo: App Path: %@", application.applicationPath);
    NSLog(@"LI:PITodo: Prefs Path: %@", application.preferencesPath);
    NSLog(@"LI:PITodo: DB Path: %@", application.databasePath);
    
    return YES;
}


// ******************************************************************************************
#pragma mark -
#pragma mark Update checking

- (BOOL)application:(FWApplication*)application shouldUpdateForDate:(NSDate*)date
{
    // Let the datasource handle update control
    return NO;
}

// ******************************************************************************************
#pragma mark -
#pragma mark Toolbar button callbacks

- (void)toggleDetailsClicked
{
    ((PIStatus*)self.application.info).toggleOn = !((PIStatus*)self.application.info).isToggleOn;
    [self triggerRedisplay];
}

- (void)disableContextsClicked
{
    // Turn off automatic context updates
    ((PIStatus*)self.application.info).autoContextOn = NO;
    ((PIStatus*)self.application.info).fixedContextOn = NO;
    ((PIStatus*)self.application.info).captionValue = nil;
    
    // Clear any contexts we're using
    [self.application clearAttribute:kPIApplicationContextCurrent];
    
    // Get new data
    [self triggerUnconditionalRefresh];
}

- (void)locationContextClicked
{
    NSNumber* show = [self.plugin.preferences objectForKey:kPIOptionsShowLocationPage];
    if (!show)
        show = [NSNumber numberWithBool:kPIOptionsShowLocationPageDefault];
    
    if (![show boolValue]) {
        NSArray* locations = [PIIntegration locationContextsFromPI];
        [self.application setAttribute:kPIApplicationContextCurrent value:locations];
        
        ((PIStatus*)self.application.info).autoContextOn = YES;
        ((PIStatus*)self.application.info).fixedContextOn = NO;
        
        [self triggerUnconditionalRefresh];
    }
    else {
        CGSize screenSize = FWGetCurrentScreenSize();
        CGRect rect = CGRectMake(0, 20, screenSize.width, screenSize.height - 20);

        PIContextList* previewData = [[[PIContextList alloc] initWithPreferences:self.preferences] autorelease];
        
        FWDetailListView *thePreview = [[[FWDetailListView alloc] initWithFrame:rect
                                                                           list:[NSArray arrayWithObjects:@"X", nil]
                                                                          index:0
                                                                        caption:@"ListView/Locations"
                                                                    application:self.application
                                                                       delegate:previewData] autorelease];
        
        [self.plugin showPreview:thePreview];
    }
}

-(void)manualContextClicked
{
    CGSize screenSize = FWGetCurrentScreenSize();
    CGRect rect = CGRectMake(0, 20, screenSize.width, screenSize.height - 20);
    
    PIContextSelectList* previewData = [[[PIContextSelectList alloc] initWithKey:kPIApplicationContextList1
                                                                     preferences:self.preferences] autorelease];

    FWDetailListView *thePreview = [[[FWDetailListView alloc] initWithFrame:rect
                                                                       list:[NSArray arrayWithObjects:@"X", nil]
                                                                      index:0
                                                                    caption:@"ListView/Contexts"
                                                                application:self.application
                                                                   delegate:previewData] autorelease];

    [self.plugin showPreview:thePreview];
}

-(void)newTodoClicked
{
    CGSize screenSize = FWGetCurrentScreenSize();
    CGRect rect = CGRectMake(0, 20, screenSize.width, screenSize.height - 20);

    PINewTodo* newTodo = [[[PINewTodo alloc] initWithFrame:rect application:self.application preferences:self.preferences] autorelease];
    [self.plugin showPreview:newTodo];
}


// ******************************************************************************************
#pragma mark -
#pragma mark Badge update callback

- (void)badgeUpdate:(NSNotification*)notif
{
    NSLog(@"LI:PITodo: badge update %@", notif);
    
    if (NSNumber* badge = [notif.userInfo objectForKey:@"badge"]) {
        NSString* value = [badge stringValue];

        if (![((PIStatus*)self.application.info).badgeValue isEqualToString:value]) {
            NSLog(@"LI:PITodo: New badge value: %@", value);

            ((PIStatus*)self.application.info).badgeValue = value;
            if (((PIStatus*)self.application.info).isBadgeOn)
                [self setBadgeValue:value hidden:NO];
        }
    }
}

@end
